package com.ltedu.system.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ltedu.common.contants.Constants;
import com.ltedu.common.domain.SecurityUser;
import com.ltedu.common.dto.UserDTO;
import com.ltedu.common.enums.ErrorCodeEnum;
import com.ltedu.common.exception.BaseException;
import com.ltedu.common.redis.RedisTool;
import com.ltedu.common.utils.MD5Utils;
import com.ltedu.common.utils.SecurityUtils;
import com.ltedu.common.vo.Result;
import com.ltedu.system.domain.SysUser;
import com.ltedu.system.domain.SysUserRole;
import com.ltedu.system.domain.vo.SysUserVO;
import com.ltedu.system.mapper.SysUserMapper;
import com.ltedu.system.service.SysPermissionService;
import com.ltedu.system.service.SysRoleService;
import com.ltedu.system.service.SysUserRoleService;
import com.ltedu.system.service.SysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 * 后台用户信息 服务实现类
 * </p>
 *
 * @author Jerry
 * @since 2020-11-27
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysUserRoleService userRoleService;

    @Autowired
    private SysPermissionService sysPermissionService;

    @Autowired
    private RedisTool redisTool;

    /**
     * 保存用户
     *
     * @param sysUserVo
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean save(SysUserVO sysUserVo) {
        // 判断用户是否已注册过
        this.isRegisted(sysUserVo.getUsername());

        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(sysUserVo, sysUser);
        sysUser.setGmtCreate(new Date());
        sysUser.setGmtModified(new Date());
        sysUser.setAvatar(Constants.DEFAULT_HEAD_IMG_URL);
        String password = SecurityUtils.encryptPassword(sysUserVo.getPassword());
        sysUser.setPassword(password);
        int rows = this.baseMapper.insert(sysUser);
        if (rows == 0) {
            throw new BaseException(ErrorCodeEnum.SAVE_USER_FAIL);
        }

        saveUserRole(sysUserVo, sysUser);
        return rows > 0;
    }

    /**
     * 保存用户角色
     *
     * @param sysUserVo
     * @param sysUser
     */
    private void saveUserRole(SysUserVO sysUserVo, SysUser sysUser) {
        List<SysUserRole> userRoleList = new ArrayList<>();
        // 保存角色信息
        for (Long roleId : sysUserVo.getRoleIds()) {
            SysUserRole sysUserRole = new SysUserRole();
            sysUserRole.setState(Constants.NORMAL);
            sysUserRole.setUserId(sysUser.getId());
            sysUserRole.setRoleId(roleId);
            sysUserRole.setGmtCreate(new Date());
            sysUserRole.setGmtModified(new Date());
            userRoleList.add(sysUserRole);
        }

        boolean b = userRoleService.saveBatch(userRoleList);
        if (!b) {
            throw new BaseException(ErrorCodeEnum.SAVE_USER_ROLE_FAIL);
        }
    }

    /**
     * 更新用户
     *
     * @param sysUserVo
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(SysUserVO sysUserVo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(sysUserVo, sysUser);
        sysUser.setGmtModified(new Date());
        int rows = this.baseMapper.updateById(sysUser);
        if (rows == 0) {
            throw new BaseException(ErrorCodeEnum.UPDATE_USER_FAIL);
        }

        // 将用户角色关系删除
        userRoleService.deleteByUserId(sysUserVo.getId());

        // 重新建立用户角色关系
        saveUserRole(sysUserVo, sysUser);

        return rows > 0;
    }

    /**
     * 通过用户id找到角色列表
     *
     * @param userId 用户id
     * @return {@link Result}
     */
    @Override
    public Result findRoleListByUserId(Long userId) {
        List<Long> roleIdList = roleService.selectRoleListByUserId(userId);
        if (!CollectionUtils.isEmpty(roleIdList)) {
            throw new BaseException(ErrorCodeEnum.ROLE_NOT_FOUND);
        }
        return Result.ok(roleIdList);
    }


    /**
     * 是否注册
     *
     * @param username 用户名
     * @return {@link Boolean}
     */
    @Override
    public Boolean isRegisted(String username) {
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username)
                .eq(SysUser::getState, Constants.NORMAL);
        Integer count = this.baseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new BaseException(ErrorCodeEnum.USERNAME_IS_REGISTERED);
        }
        return count > 0;
    }

    /**
     * 更改密码
     *
     * @param username    用户名
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changePassword(String username, String oldPassword, String newPassword) {
        SecurityUser sysUser = this.findUserByUsername(username);
        if (sysUser == null) {
            throw new BaseException(ErrorCodeEnum.USER_NOT_FOUND);
        }

        // 比较密码
        String userPassword = sysUser.getPassword();
        if (!SecurityUtils.matchesPassword(oldPassword, userPassword)) {
            throw new BaseException(ErrorCodeEnum.OLD_PASSWORD_ERROR);
        }

        // 修改密码
        return updatePassword(newPassword, sysUser);
    }

    /**
     * 重置密码
     *
     * @param username 用户名
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean resetPassword(String username) {
        SecurityUser sysUser = this.findUserByUsername(username);
        if (sysUser == null) {
            throw new BaseException(ErrorCodeEnum.USER_NOT_FOUND);
        }

        // 修改密码
        return updatePassword(Constants.DEFAULT_PASSWORD, sysUser);
    }

    /**
     * 更新密码
     *
     * @param password 密码
     * @param sysUser  系统用户
     * @return {@link Boolean}
     */
    private Boolean updatePassword(String password, SecurityUser sysUser) {
        SysUser user = new SysUser();
        user.setId(sysUser.getId());
        // 密码加密
        user.setPassword(SecurityUtils.encryptPassword(password));
        int rows = this.baseMapper.updateById(user);
        if (rows == 0) {
            throw new BaseException(ErrorCodeEnum.UPDATE_USER_FAIL);
        }
        return rows > 0;
    }

    /**
     * 根据用户名查询用户信息
     *
     * @param username 用户名
     * @return {@link SysUser}
     */
    @Override
    public SecurityUser findUserByUsername(String username) {
        SysUser sysUser = this.baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().
                eq(SysUser::getUsername, username));
        SecurityUser securityUser = new SecurityUser();
        BeanUtils.copyProperties(sysUser, securityUser);
        return securityUser;
    }

    /**
     * 改变用户状态
     *
     * @param sysUserVo 系统用户签证官
     * @return {@link Boolean}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean changeUserState(SysUserVO sysUserVo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(sysUserVo, sysUser);
        sysUser.setGmtModified(new Date());
        return this.baseMapper.updateById(sysUser) > 0;
    }

    @Override
    public UserDTO loadByUsername(String username) {
        SecurityUser user = this.findUserByUsername(username);
        if (ObjectUtil.isNull(user)) {
            throw new BaseException(ErrorCodeEnum.USER_NOT_FOUND);
        }

        // 查询用户角色信息
        Set<String> roles = sysPermissionService.getRolePermission(user.getId());

        // 查询用户权限信息
        Set<String> permissions = sysPermissionService.getMenuPermission(user.getId());
        // 将权限存入缓存
        redisTool.set(username, permissions);

        SecurityUser securityUser = new SecurityUser();
        BeanUtils.copyProperties(user, securityUser);
        UserDTO userDTO = new UserDTO();
        userDTO.setUser(securityUser);
        userDTO.setRoles(roles);
        userDTO.setPermissions(permissions);
        return userDTO;
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户id
     * @return {@link UserDTO}
     */
    @Override
    public UserDTO info(Long userId) {
        SysUser sysUser = this.baseMapper.selectById(userId);
        if (ObjectUtil.isNull(sysUser)) {
            throw new BaseException(ErrorCodeEnum.USER_NOT_FOUND);
        }
        // 查询用户角色信息
        Set<String> roles = sysPermissionService.getRolePermission(sysUser.getId());

        // 查询用户权限信息
        Set<String> permissions = sysPermissionService.getMenuPermission(sysUser.getId());

        SecurityUser securityUser = new SecurityUser();
        BeanUtils.copyProperties(sysUser, securityUser);
        UserDTO userDTO = new UserDTO();
        userDTO.setUser(securityUser);
        userDTO.setRoles(roles);
        userDTO.setPermissions(permissions);
        return userDTO;
    }
}
